<?php
class User extends Generic_Record {
    public static $login_url = 'login.php';
    public static $new_pw_url = 'new_pw.php';
    
    // return the session status (user is logged in, password isn't expired)
    protected static function session_info() {
        $result = array();
        $session = new Session('THNIKAMAN');
        $session->authenticate();

        $user = isset($_SESSION['user_id']) ? static::load_by_id($_SESSION['user_id']) : false;
        if ($user) {
            $result['expired'] = $user->is_expired();
        }
        $result['user'] = $user;
        return $result;
    }

    // Sets up the translate function for the passwd field (i.e. hashes password before saving it)
    public static function initialize($db) {
        parent::initialize($db,'user',array('passwd'=>'BGCrypt::pw_hash'));
    }
    
    // Creates temporary password for given user, then saves user.
    // Returns temp password (to be sent via email or some other method).
    public static function reset_pw($username) {
        $session = new Session('THNIKAMAN');
        $session->authenticate();
        $is_expired = false;
        if ( !isset($_SESSION['user_id']) 
                || !($user = static::load_by_id($_SESSION['user_id'])) ) {
            if (!($user = static::load_by_field('name',$username))) throw new Exception('User not found');
        }
        $temp_pw = $user->temp_pw();
        $user->update(array(
            'passwd' => $temp_pw,
            'expires' => mktime(0,0,0)
            ));
        $user->save();
        return $temp_pw;
    }
    
    // Returns an instance of User with new values (still need to save!)
    public static function create($values) {
        $values['expires'] = mktime(0,0,0)+2592000;
        return parent::create($values);
    }

    // Test credentials, then start session registered to user's ID.
    public static function login($username,$pw) {
        $session = new Session('THNIKAMAN');
        $session->restart();
        $user = static::load_by_field('name',$username);
        if ( $user && $user->check_pw($pw) ) {
            $_SESSION['user_id'] = $user->get('user_id');
            return true;    
        } else return false;
    }

    // The function every user-restricted page should use.
    // Tests if they're logged in, and if their password has expired.
    public static function authenticate( $return_url = null ) {
        if ($return_url === null) $return_url = $_SERVER['PHP_SELF'];
        $info = static::session_info();
        $user = $info['user'];
        $exp = $info['expired'];
        if ( !$user || $exp ) {
            if ($return_url) {
                if ($exp) header('Location: '.static::$new_pw_url.'?expired=1&return_url='.urlencode($return_url));
                else header('Location: '.static::$login_url.'?return_url='.urlencode($return_url));
                die();
            } else throw new Exception('Authentication failed.');
        }
        return $user;
    }
    
    // Use this only on the Update Password page.  
    // They only need to be logged in to view this page.
    public static function authenticate_expired( $return_url = null ) {
        if ($return_url === null) $return_url = $_SERVER['PHP_SELF'];
        $info = static::session_info();
        if (!($user = $info['user'])) {
            if ($return_url) {
                header('Location: '.static::$login_url.'?return_url='.urlencode($return_url));
                die();
            } else throw new Exception('Not Logged In');
        }
        return $user;
    }
    
    public static function logout() {
        $session = new Session('THNIKAMAN');
        $session->end();
    }

    private function temp_pw() {
        $chars='.,|/~!@#$%^&*()_+-=[]{};:<>?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $max = strlen($chars)-1;
        $pw = '';
        for($i=0;$i<10;$i++) $pw.=$chars[rand(0,$max)];
        return $pw;
    }
    
    public function set_pw($pw) {
        if ( $this->check_pw($pw) ) return false;
        $this->update(array(
            'passwd'=>$pw,
            'expires' => mktime(0,0,0)+2592000
            ));
        return true;
    }
    
    public function check_pw($pw) {
        $saved_hash = $this->get('passwd');
        return (BGCrypt::pw_verify($pw,$saved_hash));
    }

    public function is_expired() {
        return (time() > (int) $this->get('expires'));
    }

}
?>